home *** CD-ROM | disk | FTP | other *** search
- /***********************************************************
- Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
- The Netherlands.
-
- All Rights Reserved
-
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation, and that the names of Stichting Mathematisch
- Centrum or CWI or Corporation for National Research Initiatives or
- CNRI not be used in advertising or publicity pertaining to
- distribution of the software without specific, written prior
- permission.
-
- While CWI is the initial source for this software, a modified version
- is made available by the Corporation for National Research Initiatives
- (CNRI) at the Internet address ftp://ftp.python.org.
-
- STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
- REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
- CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
- DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- PERFORMANCE OF THIS SOFTWARE.
-
- ******************************************************************/
-
- /* Float object implementation */
-
- /* XXX There should be overflow checks here, but it's hard to check
- for any kind of float exception without losing portability. */
-
- #include "allobjects.h"
- #include "modsupport.h"
-
- #include <errno.h>
- #include <ctype.h>
- #include "mymath.h"
-
- #include "protos/floatobject_protos.h"
-
- #ifdef i860
- /* Cray APP has bogus definition of HUGE_VAL in <math.h> */
- #undef HUGE_VAL
- #endif
-
- #if defined(HUGE_VAL) && !defined(CHECK)
- #define CHECK(x) if (errno != 0) ; \
- else if (-HUGE_VAL <= (x) && (x) <= HUGE_VAL) ; \
- else errno = ERANGE
- #endif
-
- #ifndef CHECK
- #define CHECK(x) /* Don't know how to check */
- #endif
-
- #ifdef HAVE_LIMITS_H
- #include <limits.h>
- #endif
-
- #ifndef LONG_MAX
- #define LONG_MAX 0X7FFFFFFFL
- #endif
-
- #ifndef LONG_MIN
- #define LONG_MIN (-LONG_MAX-1)
- #endif
-
- #ifdef __NeXT__
- #ifdef __sparc__
- /*
- * This works around a bug in the NS/Sparc 3.3 pre-release
- * limits.h header file.
- * 10-Feb-1995 bwarsaw@cnri.reston.va.us
- */
- #undef LONG_MIN
- #define LONG_MIN (-LONG_MAX-1)
- #endif
- #endif
-
- #if !defined(__STDC__) && !defined(macintosh)
- extern double fmod PROTO((double, double));
- extern double pow PROTO((double, double));
- #endif
-
- object *
- #ifdef __SC__
- newfloatobject(double fval)
- #else
- newfloatobject(fval)
- double fval;
- #endif
- {
- /* For efficiency, this code is copied from newobject() */
- register floatobject *op = (floatobject *) malloc(sizeof(floatobject));
- if (op == NULL)
- return err_nomem();
- op->ob_type = &Floattype;
- op->ob_fval = fval;
- NEWREF(op);
- return (object *) op;
- }
-
- static void
- float_dealloc(op)
- object *op;
- {
- DEL(op);
- }
-
- double
- getfloatvalue(op)
- object *op;
- {
- number_methods *nb;
- floatobject *fo;
- double val;
-
- if (op && is_floatobject(op))
- return GETFLOATVALUE((floatobject*) op);
-
- if (op == NULL || (nb = op->ob_type->tp_as_number) == NULL ||
- nb->nb_float == NULL) {
- err_badarg();
- return -1;
- }
-
- fo = (floatobject*) (*nb->nb_float) (op);
- if (fo == NULL)
- return -1;
- if (!is_floatobject(fo)) {
- err_setstr(TypeError, "nb_float should return float object");
- return -1;
- }
-
- val = GETFLOATVALUE(fo);
- DECREF(fo);
-
- return val;
- }
-
- /* Methods */
-
- void float_buf_repr Py_PROTO((char*,floatobject*));
-
- void
- float_buf_repr(buf, v)
- char *buf;
- floatobject *v;
- {
- register char *cp;
- /* Subroutine for float_repr and float_print.
- We want float numbers to be recognizable as such,
- i.e., they should contain a decimal point or an exponent.
- However, %g may print the number as an integer;
- in such cases, we append ".0" to the string. */
- sprintf(buf, "%.12g", v->ob_fval);
- cp = buf;
- if (*cp == '-')
- cp++;
- for (; *cp != '\0'; cp++) {
- /* Any non-digit means it's not an integer;
- this takes care of NAN and INF as well. */
- if (!isdigit(Py_CHARMASK(*cp)))
- break;
- }
- if (*cp == '\0') {
- *cp++ = '.';
- *cp++ = '0';
- *cp++ = '\0';
- }
- }
-
- /* ARGSUSED */
- static int
- float_print(v, fp, flags)
- floatobject *v;
- FILE *fp;
- int flags; /* Not used but required by interface */
- {
- char buf[100];
- float_buf_repr(buf, v);
- fputs(buf, fp);
- return 0;
- }
-
- static object *
- float_repr(v)
- floatobject *v;
- {
- char buf[100];
- float_buf_repr(buf, v);
- return newstringobject(buf);
- }
-
- static int
- float_compare(v, w)
- floatobject *v, *w;
- {
- double i = v->ob_fval;
- double j = w->ob_fval;
- return (i < j) ? -1 : (i > j) ? 1 : 0;
- }
-
- static long
- float_hash(v)
- floatobject *v;
- {
- double intpart, fractpart;
- int expo;
- long x;
- /* This is designed so that Python numbers with the same
- value hash to the same value, otherwise comparisons
- of mapping keys will turn out weird */
-
- #ifdef MPW /* MPW C modf expects pointer to extended as second argument */
- {
- extended e;
- fractpart = modf(v->ob_fval, &e);
- intpart = e;
- }
- #else
- fractpart = modf(v->ob_fval, &intpart);
- #endif
-
- if (fractpart == 0.0) {
- if (intpart > 0x7fffffffL || -intpart > 0x7fffffffL) {
- /* Convert to long int and use its hash... */
- object *w = dnewlongobject(v->ob_fval);
- if (w == NULL)
- return -1;
- x = hashobject(w);
- DECREF(w);
- return x;
- }
- x = (long)intpart;
- }
- else {
- fractpart = frexp(fractpart, &expo);
- fractpart = fractpart*2147483648.0; /* 2**31 */
- x = (long) (intpart + fractpart) ^ expo; /* Rather arbitrary */
- }
- if (x == -1)
- x = -2;
- return x;
- }
-
- static object *
- float_add(v, w)
- floatobject *v;
- floatobject *w;
- {
- return newfloatobject(v->ob_fval + w->ob_fval);
- }
-
- static object *
- float_sub(v, w)
- floatobject *v;
- floatobject *w;
- {
- return newfloatobject(v->ob_fval - w->ob_fval);
- }
-
- static object *
- float_mul(v, w)
- floatobject *v;
- floatobject *w;
- {
- return newfloatobject(v->ob_fval * w->ob_fval);
- }
-
- static object *
- float_div(v, w)
- floatobject *v;
- floatobject *w;
- {
- if (w->ob_fval == 0) {
- err_setstr(ZeroDivisionError, "float division");
- return NULL;
- }
- return newfloatobject(v->ob_fval / w->ob_fval);
- }
-
- static object *
- float_rem(v, w)
- floatobject *v;
- floatobject *w;
- {
- double vx, wx;
- double /* div, */ mod;
- wx = w->ob_fval;
- if (wx == 0.0) {
- err_setstr(ZeroDivisionError, "float modulo");
- return NULL;
- }
- vx = v->ob_fval;
- mod = fmod(vx, wx);
- /* div = (vx - mod) / wx; */
- if (wx*mod < 0) {
- mod += wx;
- /* div -= 1.0; */
- }
- return newfloatobject(mod);
- }
-
- static object *
- float_divmod(v, w)
- floatobject *v;
- floatobject *w;
- {
- double vx, wx;
- double div, mod;
- wx = w->ob_fval;
- if (wx == 0.0) {
- err_setstr(ZeroDivisionError, "float divmod()");
- return NULL;
- }
- vx = v->ob_fval;
- mod = fmod(vx, wx);
- div = (vx - mod) / wx;
- if (wx*mod < 0) {
- mod += wx;
- div -= 1.0;
- }
- return mkvalue("(dd)", div, mod);
- }
-
- static double powu(x, n)
- double x;
- long n;
- {
- double r = 1.;
- double p = x;
- long mask = 1;
- while (mask > 0 && n >= mask) {
- if (n & mask)
- r *= p;
- mask <<= 1;
- p *= p;
- }
- return r;
- }
-
- static object *
- float_pow(v, w, z)
- floatobject *v;
- object *w;
- floatobject *z;
- {
- double iv, iw, ix;
- long intw;
- /* XXX Doesn't handle overflows if z!=None yet; it may never do so :(
- * The z parameter is really only going to be useful for integers and
- * long integers. Maybe something clever with logarithms could be done.
- * [AMK]
- */
- iv = v->ob_fval;
- iw = ((floatobject *)w)->ob_fval;
- intw = (long)iw;
- if (iw == intw && -10000 < intw && intw < 10000) {
- /* Sort out special cases here instead of relying on pow() */
- if (intw == 0) { /* x**0 is 1, even 0**0 */
- if ((object *)z!=None) {
- ix=fmod(1.0, z->ob_fval);
- if (ix!=0 && z->ob_fval<0) ix+=z->ob_fval;
- }
- else ix=1.0;
- return newfloatobject(ix);
- }
- errno = 0;
- if (intw > 0)
- ix = powu(iv, intw);
- else
- ix = 1./powu(iv, -intw);
- }
- else {
- /* Sort out special cases here instead of relying on pow() */
- if (iv == 0.0) {
- if (iw < 0.0) {
- err_setstr(ValueError,
- "0.0 to a negative power");
- return NULL;
- }
- return newfloatobject(0.0);
- }
- if (iv < 0.0) {
- err_setstr(ValueError,
- "negative number to a float power");
- return NULL;
- }
- errno = 0;
- ix = pow(iv, iw);
- }
- CHECK(ix);
- if (errno != 0) {
- /* XXX could it be another type of error? */
- err_errno(OverflowError);
- return NULL;
- }
- if ((object *)z!=None) {
- ix=fmod(ix, z->ob_fval); /* XXX To Be Rewritten */
- if ( ix!=0 &&
- ((iv<0 && z->ob_fval>0) || (iv>0 && z->ob_fval<0) )) {
- ix+=z->ob_fval;
- }
- }
- return newfloatobject(ix);
- }
-
- static object *
- float_neg(v)
- floatobject *v;
- {
- return newfloatobject(-v->ob_fval);
- }
-
- static object *
- float_pos(v)
- floatobject *v;
- {
- INCREF(v);
- return (object *)v;
- }
-
- static object *
- float_abs(v)
- floatobject *v;
- {
- if (v->ob_fval < 0)
- return float_neg(v);
- else
- return float_pos(v);
- }
-
- static int
- float_nonzero(v)
- floatobject *v;
- {
- return v->ob_fval != 0.0;
- }
-
- static int
- float_coerce(pv, pw)
- object **pv;
- object **pw;
- {
- if (is_intobject(*pw)) {
- long x = getintvalue(*pw);
- *pw = newfloatobject((double)x);
- INCREF(*pv);
- return 0;
- }
- else if (is_longobject(*pw)) {
- *pw = newfloatobject(dgetlongvalue(*pw));
- INCREF(*pv);
- return 0;
- }
- return 1; /* Can't do it */
- }
-
- static object *
- float_int(v)
- object *v;
- {
- double x = getfloatvalue(v);
- if (x < 0 ? (x = ceil(x)) < (double)LONG_MIN
- : (x = floor(x)) > (double)LONG_MAX) {
- err_setstr(OverflowError, "float too large to convert");
- return NULL;
- }
- return newintobject((long)x);
- }
-
- static object *
- float_long(v)
- object *v;
- {
- double x = getfloatvalue(v);
- return dnewlongobject(x);
- }
-
- static object *
- float_float(v)
- object *v;
- {
- INCREF(v);
- return v;
- }
-
-
- static number_methods float_as_number = {
- (binaryfunc)float_add, /*nb_add*/
- (binaryfunc)float_sub, /*nb_subtract*/
- (binaryfunc)float_mul, /*nb_multiply*/
- (binaryfunc)float_div, /*nb_divide*/
- (binaryfunc)float_rem, /*nb_remainder*/
- (binaryfunc)float_divmod, /*nb_divmod*/
- (ternaryfunc)float_pow, /*nb_power*/
- (unaryfunc)float_neg, /*nb_negative*/
- (unaryfunc)float_pos, /*nb_positive*/
- (unaryfunc)float_abs, /*nb_absolute*/
- (inquiry)float_nonzero, /*nb_nonzero*/
- 0, /*nb_invert*/
- 0, /*nb_lshift*/
- 0, /*nb_rshift*/
- 0, /*nb_and*/
- 0, /*nb_xor*/
- 0, /*nb_or*/
- (coercion)float_coerce, /*nb_coerce*/
- (unaryfunc)float_int, /*nb_int*/
- (unaryfunc)float_long, /*nb_long*/
- (unaryfunc)float_float, /*nb_float*/
- 0, /*nb_oct*/
- 0, /*nb_hex*/
- };
-
- typeobject Floattype = {
- OB_HEAD_INIT(&Typetype)
- 0,
- "float",
- sizeof(floatobject),
- 0,
- (destructor)float_dealloc, /*tp_dealloc*/
- (printfunc)float_print, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- (cmpfunc)float_compare, /*tp_compare*/
- (reprfunc)float_repr, /*tp_repr*/
- &float_as_number, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- (hashfunc)float_hash, /*tp_hash*/
- };
-